#ifndef SimulateBASE_H
#define SimulateBASE_H

#include "circuit.h"
#include <fstream>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <stdlib.h>
#include <math.h>
#include "pareto.h"
#include <cassert>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#include <sstream>

typedef struct resVal_{
        
        int DFF_id;
        int val;
        
}resVal;

typedef struct resMap_{
        
        int DFF_id;
        map<int,double> R;
        set<int> R0;
        set<int> R1;
        vector<resVal> R0_P;
        vector<resVal> R1_P;
        double P0;
        double P1;
        double weight;
        
}resMap;

typedef struct T_resMap_{
        
        int DFF_id;
        set<int> R0_seq;
        set<int> R0_com;
        set<int> R1_seq;
        set<int> R1_com;
        vector<resVal> R0_seq_P;
        vector<resVal> R0_com_P;
        vector<resVal> R1_seq_P;
        vector<resVal> R1_com_P;
        double P0;
        double P1;
        double weight;
        double weight_DFF;
        double weight_Com;
        
}TresMap;


typedef struct rate_{
        
        double weight;
        vector<resMap*>::iterator it_map;
        
}mapRate;

typedef struct t_rate_{
        
        double weight;
        vector<TresMap*>::iterator it_map;
        
}TmapRate;

class Simulate;

typedef struct sample_
{
        vector<int> DFF_ids;
        double VN;
        
}sample;

typedef struct myRetarg_
{
        long int Tid;
        double VN;
}myRetarg;


typedef struct myWorkarg_
{
        long int Tid;
        Simulate *Sim;
}myWorkarg;

typedef struct SG_
{
        list<Signal*> SL;
}SG;


class Simulate{
        
  public:
        ~Simulate();
  Simulate(Circuit *C):Ci(C) {}
        
        void SetProb();
        void updateRStime();
        void updateRSmapWeight(vector<resMap*>&);
        void PickTop3MostFanout();
        bool PreSimHybrid1Trace();
        void PrintRestoreMap(int Tid);
        bool PrintSignalBitVal(Signal* sig, int Tid);
        double MultCalVN(int Tid);
        double MultCalVNWOLOCK(int Tid);
        void initMultThread(int thread_num);
        bool LoadInitDFFValue(int offset, int Tid);
        
        bool SimInitDFFValue();//fixed at 2 * TRACE_DEPTH_NUM * 8 *
                               //sizeof(myDataType)
        bool SimInitDFFValue(string filename);
        bool LoadDFFMap(string filename);
        
        double MultComputVN(int offset);
        double exhaustiveComputVN();
        double exhaustiveComputVN(bool);
        bool exhaustiveSimTraced();
        void initTraceBuffer();
        bool fill_value(const bool Dir, const int cycle_number);
        bool restore_event(const bool Dir, const int cycle_number);
        void initPruning();
        void initSimulateHybrid();
        void initSimulateHybrid_PRUNE(int);
        void initSimulateHybrid_GREEDY(int);
        void initSimulate(bool);
        void initSimulateGolden(void);
        
        void DFFSearchNearby();
        void addIslands(vector<int> &selected_traces, double VN_bar);
        void Sample_Procedure(const int sample_times);
        bool DFS_Forward(Node* ni, const int DFF_id, vector<Node*>& PassedNodes);
        bool DFS_Backward(Node* ni, const int DFF_id, vector<Node*>& PassedNodes);
        void setSigValues(vector<Signal *> sigs, vector<Value> vals, int Tid);
        void setSigValues(vector<Signal *> sigs, vector<Value> vals);
        void setTraceValues(vector<Value> vals);
        
        pair<double, double> simSelect(const int trace_size, const char* filename);
        double simSelectValeria(const int trace_size, const char* filename);
        bool simHybrid(void);
        bool simBackandForce(void);
        bool simHybrid(int);
        bool simBackandForce1Trace(void);
        bool simHybrid1Trace(bool test);
        bool checkTermination(const bool Dir, list<Signal*>& sigList);
        
        bool sim1cycle(void);
        bool sim1cycleBackward(void);
        bool sim1cycleExh(void);
        void simNcycle(int n);
        
        void simProb(int n);
        void simProb(int n, string filename);
        bool PrintMyDataType(myDataType f);
                
        void initMultithread_GREEDY(int thread_num);        
        void initMultithread_PRUNE(int thread_num);
//#ifndef MULTITHREAD
        void sim_event(bool);
        bool sim_event_cycle1(void);
        bool sim_event_back_cycle1(void);
        void initSimulate(void);
//#else
        void sim_event(bool,int);
        bool sim_event_cycle1(int);
        bool sim_event_back_cycle1(int);
        void initSimulate(int);
//#endif
        
        void findVicinityFlipflop(int DFF_id, vector<resVal> &R_seq_P, set<int> &R_seq, int dir);
        double Check_Traces(const int trace_size);
        double Check_Traces(const int, string&);
        void sim_event_cycle(void);
        bool simAllCycle();
        void simNcycleBackward(int n);
        bool simAllCycleBackward();
        void forwardSimReg(int n);
        void forwardSim_event(int n);
        void forwardGolden(int n);
        void backwardSimReg(void);
        
        void dump(void);
        void dumpOutput(void);
        
        void setResets(void);
        void initGates(void);
        
        void hueristicSelect(const char* filename, const int trace_size);
        void hueristicSelect2(const int trace_size, const char* filename);
        double huerSelect2ProcessFor1(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        double huerSelect2ProcessFor2(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces, const char* filename);//our approach
        double huerSelect2ProcessFor2Com(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces, const char* filename);
        double huerSelect2ProcessFor2Mult(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        double huerSelect2ProcessFor2Mod(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        double huerSelect2ProcessBack(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        double huerSelect2ProcessBackMod(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        double huerSelect3Process(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces);
        void hueristicSelect3(const int trace_size, const char* filename);
        pair<double, double> biasedSelect(const int trace_size, const char* filename, const double lampda);
        pair<double, double> huerSelectBiasedProcess(const int trace_size, vector<TresMap*> &Mymap , vector<int> &selected_traces, const char* filename, const double lampda);
        void assignRandomWeight(const int crit_gate_num);
        void finalHeuSelect(const int trace_size, const char* filename, const double lampda);
        double finalHeuSelectProcess(const int trace_size, vector<resMap*> &Mymap , vector<int> &selected_traces, const char* filename);

//#ifndef MULTITHREAD
        void simTraced(int cn);
        double computVN();
//#else
        void simTraced(int cn, int Tid);
        double computVN(int);
//#endif
        
        pair<double,double> reportSRR_GRR(void);
        
        double computVN(char *filename);
        Signal* getTraced(int i) {return tracedSigs[i];}
        void addTraced(Signal* s) {tracedSigs.push_back(s);}
        int tracedSize(void) {return tracedSigs.size();}

        void printTraced(){
                
                for(int i = 0; i < tracedSigs.size(); i++)
                        cout<<tracedSigs[i]->getName()<<"\t";
                
                cout << endl;
                
        }
        
        void clearTraced()
        { 
                tracedSigs.clear();
        }
	
        long sim_round;
        int trace_depth;
        Circuit *Ci;
        //struct lessRStime{}; 
        /*
        struct lessRStime{ 
                bool operator()(int i1, int i2)
                {
                        return (Ci->getFlipflop(i1)->getOutput(0)->RStime < Ci->getFlipflop(i2)->getOutput(0)->RStime);
                }
        };
        */
        vector<Node*> passive;
        vector<Signal*> tracedSigs;
        vector<Signal*> lessRSedSignals;
        map<int, vector<Node*> > MulTPassiveGates;
        map<int, vector<Signal*> > MulTVNCollector;
        
        SG* sigList;
        Signal** CurSig;
        //map<int , list<Signal*> > sigList;
        //map<int , Signal*> CurSig;
        map< int, vector<Signal*> >sig;
        map< int, vector<Value> >val;
        vector<int> islands;

  protected:
        vector<Node*> passiveGates;
        ofstream dumpFile;
};

/*
struct lessRStime:public binary_function<int, int, bool>{ 
        bool operator()(int i1, int i2)
        {
                return (Ci->getFlipflop(i1)->getOutput(0)->RStime < Ci->getFlipflop(i2)->getOutput(0)->RStime);
        }
};
        

struct longSequence : public binary_function<map<int, set<int> >::iterator, map<int, set<int> >::iterator, bool> {
        bool operator()(map<int, set<int> >::iterator it_a, map<int, set<int> >::iterator it_b){
                return ((*it_a).second.size() > (*it_b).second.size());
        }
};
*/

#endif
